/*
 * Copyright 2011 The Rusted Roof, LLC.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *        http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

package org.proteusframework.core.base.config;


import org.proteusframework.core.api.config.IConfigProperty;
import org.proteusframework.core.api.config.IConfigPropertyPrototype;
import org.proteusframework.core.util.Assert;

/**
 * Builder used to create either {@link org.proteusframework.core.api.config.IConfigPropertyPrototype} instances
 * used to define a configuration property, or a physical run-time configuration property represented by an
 * {@link org.proteusframework.core.api.config.IConfigProperty}.
 * <p/>
 * Typically an {@link org.proteusframework.core.api.config.IConfigProperty} only uses the constructor and the
 * {@link #assignValue(Object)}.
 *
 * @author Tacoma Four
 */
public final class ConfigPropertyBuilder
{
    /**
     * Configuration property key.
     */
    private String key;

    /**
     * Configuration property description.
     */
    private String description;

    /**
     * Configuration property example value.
     */
    private String example;

    /**
     * Flag that indicates if the configuration property is mandatory.
     */
    private boolean isMandatory = false;

    /**
     * Default value, if defined, for the configuration property.
     */
    private Object defaultValue = null;

    /**
     * Assigned value (runtime) of the configuration property.
     */
    private Object assignedValue;

    /**
     * Initializes the builder to create either an IConfigPropertyPrototype or an IConfigProperty associated with the
     * given key.
     *
     * @param key Property key
     */
    public ConfigPropertyBuilder(final String key)
    {
        Assert.parameterNotNull(key, "Parameter 'key' must not be null");
        this.key = key;
    }

    /**
     * Initializes the builder to create an {@link IConfigProperty} based on the provided property prototype.
     *
     * @param prototype Property prototype
     */
    public ConfigPropertyBuilder(final IConfigPropertyPrototype prototype)
    {
        Assert.parameterNotNull(prototype, "Parameter 'prototype' must not be null");
        this.key = prototype.getKey();
        this.description = prototype.getDescription();
        this.example = prototype.getExample();
        this.isMandatory = prototype.isMandatory();
        this.defaultValue = prototype.getDefaultValue();
    }

    /**
     * Adds a description to the property.
     * <p/>
     * This method is typically only invoked when defining an
     * {@link org.proteusframework.core.api.config.IConfigPropertyPrototype}
     *
     * @param description Description of the property
     * @return builder
     */
    public ConfigPropertyBuilder setDescription(String description)
    {
        this.description = description;
        return this;
    }

    /**
     * Adds an example to the property.
     * <p/>
     * This method is typically only invoked when defining an
     * {@link org.proteusframework.core.api.config.IConfigPropertyPrototype}
     *
     * @param example Property example
     * @return builder
     */
    public ConfigPropertyBuilder setExample(String example)
    {
        this.example = example;
        return this;
    }

    /**
     * Identifies that the property is considered mandatory.
     * <p/>
     * This method is typically only invoked when defining an
     * {@link org.proteusframework.core.api.config.IConfigPropertyPrototype}
     *
     * @param flag true, if the property is mandatory
     * @return builder
     */
    public ConfigPropertyBuilder setMandatory(boolean flag)
    {
        this.isMandatory = flag;
        return this;
    }

    /**
     * Default value assigned to the property if a run-time value is not assigned.
     * <p/>
     * This method is typically only invoked when defining an
     * {@link org.proteusframework.core.api.config.IConfigPropertyPrototype}
     *
     * @param defaultValue Default value
     * @return builder
     */
    public ConfigPropertyBuilder setDefaultValue(Object defaultValue)
    {
        this.defaultValue = defaultValue;
        return this;
    }

    /**
     * Assigns the run-time value associated with the property key.
     *
     * @param assignedValue Run-time value assigned to the property key
     * @return builder
     */
    public ConfigPropertyBuilder assignValue(Object assignedValue)
    {
        this.assignedValue = assignedValue;
        return this;
    }

    /**
     * Uses the values from the builder to construct an IConfigPropertyPrototype.
     *
     * @return Property prototype
     */
    public IConfigPropertyPrototype buildPrototype()
    {
        return new IConfigPropertyPrototype()
        {
            @Override
            public String getKey()
            {
                return key;
            }

            @Override
            public String getDescription()
            {
                return description;
            }

            @Override
            public String getExample()
            {
                return example;
            }

            @Override
            public boolean isMandatory()
            {
                return isMandatory;
            }

            @Override
            public Object getDefaultValue()
            {
                return defaultValue;
            }
        };
    }

    /**
     * Uses the values of the builder to construct an IConfigProperty.
     *
     * @return Run-time property
     */
    public IConfigProperty buildProperty()
    {

        return new IConfigProperty()
        {
            @Override
            public String getKey()
            {
                return key;
            }

            @Override
            public String getDescription()
            {
                return description;
            }

            @Override
            public String getExample()
            {
                return example;
            }

            @Override
            public boolean isMandatory()
            {
                return isMandatory;
            }

            @Override
            public Object getDefaultValue()
            {
                return defaultValue;
            }

            @Override
            public Object getAssignedValue()
            {
                return assignedValue;
            }
        };
    }
}
